/**
 * Task Calculator for Google Calendar
 *
 * Copyright (C) 2007 Firma JAKUBIAK Antoni Jakubiak
 * http://www.jakubiak.biz/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * Create task from GData entry
 * @param entry GData
 */ 
function Task(entry) {
	this.title = entry.title.$t;
	this.start = this._parseDate(entry['gd$when'][0].startTime);
	this.end   = this._parseDate(entry['gd$when'][0].endTime);
	this.time  = new Date();
	if(this.end) {
		this.time.setTime(this.end.getTime() - this.start.getTime());
	} else {
		this.time.setTime(0);
	}
}		
 
/**
 * Parse date
 * @private 
 */
Task.prototype._parseDate = function dateString(dateString) {
	var re = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d)/; // T(\d\d:\d\d)");
	
	if(!re.test(dateString)) return null;
	var m = re.exec(dateString);
	for(var i = 1; i<=5; i++) {
		var s = new String(m[i]);
		while(s.length>1 && "0"==s.charAt(0)) {
			s = s.slice(1);
		}
		m[i] = parseInt(s);
	}
//	var date = new Date( Date.UTC(m[1], m[2] - 1, m[3], m[4], m[5], 0) );
	var date = new Date( m[1], m[2] - 1, m[3], m[4], m[5], 0 );
//	alert(dateString+"\n"+m[1]+"-"+m[2]+"-"+m[3]+" "+m[4]+":"+m[5]+"\n"+date);
	return date;
	
	
}




/**
 * Create report
 * @param iRegExp math to title
 * @param iStartMin date have to be after this
 * @param iStartMax date have to be before this
 */
function Report(iRegExp,iStartMin,iStartMax) {
	this.regExp = iRegExp;
	this.startMin = iStartMin;
	this.startMax = iStartMax;
	this.minDate  = null;
	this.maxDate  = null;
	this.sum	  = new Date(0);
	this.tasks    = new Array();
}

/**
 * Test if task match to this report
 * @param Task task
 * @return true if task match reporti criteria
 */
Report.prototype.test = function(task) {
	if(this.regExp&& ! this.regExp.test(task.title)) {
		// title of task does not pass search criteria
		return false;
	}
	if(!task.start) {
		// prawdopodobnie mamy calodniowy event, 
		// pomijamy go
		return false;
	}
	if(this.startMin && this.startMin.getTime() > task.start.getTime()) {
		// task start befor startMin
		return false;
	}
	if(this.startMax && this.startMax.getTime() < task.start.getTime()) {
		// task start after startMax
		return false;
	}
	return true;
}

/**
 * If task pass to report criteria collect it
 * @param Array of Task iTasks
 */
Report.prototype.addAll = function(iTasks) {
	// report criteria
	for( var i in iTasks ) {
		if( this.test(iTasks[i]) ) {
			this.tasks.push( iTasks[i] );
		}
	}
	// report results
	for( var i in this.tasks ) {
		var task = this.tasks[i];
		this.sum.setTime( this.sum.getTime() + task.time.getTime() );
	}
}

/**
 * Return total time HH:MM
 */
Report.prototype.getSumHhmm = function() {
	var minutes = Math.round( this.sum.getTime() / (60 * 1000) );
	var hh = Math.floor(minutes/60)
	var mm = minutes % 60;
	return hh + ":" + (mm<10?"0":"")+mm;
}












/**
 * Constructor
 */ 
function TaskCalculator() {
	TaskCalculator.instance = this;
	this.tasks = new Array();
	this._summaryHtml = "";
	this._monthlyHtml = "";
	this._allHtml = "";
}

/**
 * JSON Callback
 */
function taskCalculatorCallback(root) {
	TaskCalculator.instance._onloadCallback(root);
}

/**
 * Set URL with private google calendar xml
 * @param iUrl
 */
TaskCalculator.prototype.setUrl = function(iUrl) {
	this.url = iUrl.replace(/basic$/, "full-noattendees");
}
/**
 * This method will be invoke after loading data from Google
 * Overwrite it!
 */ 
TaskCalculator.prototype.onload = function() {
}





/**
 * Create query to google, download data and parse it
 * TODO, shoud be fix to fetch data in smaller parts
 */
TaskCalculator.prototype.run = function() {
	var startMin="2006-01-01T00:00:00";
	var startMax="2016-12-31T23:59:59";
	var maxResults=500;
	var url = this.url + "?alt=json-in-script&callback=taskCalculatorCallback&orderby=starttime&singleevents=true";
	url = url +"&start-min="+startMin;
	url = url +"&start-max="+startMax;
	url = url +"&max-results="+maxResults;
	this.tasks = new Array();
	this._load(url);
}




/**
 * Set extra tags to search
 * @param array iLabels
 */ 
TaskCalculator.prototype.setLabels = function(iLabels) {
	this.labels = iLabels;
}


/**
 * Summary
 */
TaskCalculator.prototype.getSummaryHtml = function() {
	return this._summaryHtml;
}
TaskCalculator.prototype.getMonthlyHtml = function() {
	return this._monthlyHtml;
}
TaskCalculator.prototype.getAllHtml = function() {
	return this._allHtml;
}




/**
 * JavaScript Request
 * @private
 */
TaskCalculator.prototype._load = function(url) {
	var jsNode = document.createElement("script");
	jsNode.type = "text/javascript";
	jsNode.charset = "utf-8";
	jsNode.src = url;
	var headNode = document.getElementsByTagName("head").item(0);
	headNode.appendChild(jsNode);
}



/**
 * Load data from Google Calendar and store it local
 */
TaskCalculator.prototype._parseEntries = function(root) {
    var feed = root.feed;
    var entries = feed.entry || [];
    for (var i = 0; i < entries.length; ++i) {
    	var entry = feed.entry[i];
    	var task = new Task(entry);
		this.tasks.push( task );
    }
}

/**
 * Get min date from tasks
 */
TaskCalculator.prototype._getMinDate = function() {
	var min = null;
	for( var i in this.tasks ) {
		var task = this.tasks[i];
		if(task.start) {
			if ( min == null ) {
				min = task.start;
			} 
			if( min > task.start ) {
				min = task.start;
			}
		}
	}
	return min;	
}

/**
 * Wyswietlanie komunikatow bledu
 */
function debug(msg) {
	var el = document.getElementById("debug");
	if(el) {
		el.innerHTML = el.innerHTML + "<br>" + msg;
	}
}


/**
 * Get max date from tasks
 */
TaskCalculator.prototype._getMaxDate = function() {
	var max = null;	
	for( var i in this.tasks ) {
		var task = this.tasks[i];
		if(task.end) {
			if( max == null ) {
				max = task.end;
			}
			if( max < task.end ) {
				max = task.end;
			}
		}
	}
	return max;	
}





/**
 * Create summary html
 */
TaskCalculator.prototype._createSummaryHtml = function() {
    this.summaryReport = new Report(null,null,null);
    this.summaryReport.addAll( this.tasks ) ;
    
    var html = "<table class='report'>";
    html = html + "<tr><th>Total:</th><td>" + this.summaryReport.getSumHhmm() + "</td></tr>";
    for(var i in this.labels) {
    	var label = this.labels[i];
    	var report = new Report( new RegExp(label,"i"), null, null );
    	report.addAll( this.tasks );
    	html = html + "<tr><th>" + label + ":</th><td> " + report.getSumHhmm() + "</td></tr>";
    }
    html = html + "<tr><th>From:</th><td>" + this._getMinDate() + "</td></tr>";
    html = html + "<tr><th>To:</th><td>" + this._getMaxDate() + "</td></tr>";
    this._summaryHtml = html;
}

/**
 * Create monthly reports
 */
TaskCalculator.prototype._createMonthlyHtml = function() {
	var html = "<table class='report'><tr><th>Month</th><th>Total</th>";
	for (var i in this.labels) {
    	html = html + "<th>" + this.labels[i] + "</th>";
    } 
    html = html + "</tr>";
    var start = new Date(); start.setTime(this._getMinDate().getTime()); start.setDate(1);
    start = this.midnight(start);
    var end = new Date(); end.setTime(this._getMaxDate().getTime()); end.setDate(1); end.setMonth(end.getMonth()+1);
    end = this.midnight(end);
    for (var i = start; i < end; i.setMonth(i.getMonth()+1) ) {
    	html = html + "<tr><td>" + i.getFullYear() + "-" + (i.getMonth()<9?"0":"")+(i.getMonth()+1) + "</td>";
    	var j = new Date(); j.setTime(i.getTime()); j.setMonth(j.getMonth()+1);
    	var report = new Report(null, i, j);
    	report.addAll( this.tasks );
    	html = html + "<td>" + report.getSumHhmm() + "</td>";
    	for(var k in this.labels) {
	    	var label = this.labels[k];
    		var report2 = new Report( new RegExp(label,"i"), i, j );
    		report2.addAll( this.tasks );
    		html = html + "<td>" + report2.getSumHhmm() + "</td>";
    	}
    	html += "</tr>";
    }
    html = html + "</table>";
    this._monthlyHtml = html;
}

/**
 * Zwraca polnoc
 */
TaskCalculator.prototype.midnight = function(myDate) {
	var d = new Date();
	d.setTime(myDate.getTime());
	d.setHours(0); 
	d.setMinutes(0); 
	d.setSeconds(0); 
	d.setMilliseconds(0);
	return d;
} 
	

/**
 * Create all reports
 */
TaskCalculator.prototype._createAllHtml = function() {
	var html = "<table class='report'><tr><th>Date</th><th>Start</th><th>End</th><th>Sum</th><th>Description</th></tr>";
	for ( var i in this.tasks ) {
		var task = this.tasks[i];
		html = html + "<tr><td>" + this._printDate(task.start) + "</td>";
		html = html + "<td>" + this._printHour(task.start) + "</td>";   
		html = html + "<td>" + this._printHour(task.end) + "</td>";
		html = html + "<td>" + this._printSum(task.time) + "</td>";
		html = html + "<td>" + task.title + "</td>";
		html = html + "</tr>";
	}
	html = html + "</table>";
	this._allHtml = html;
}

/**
 * return date in yyyy-mm-dd format
 */
TaskCalculator.prototype._printDate = function(date) {
	try {
		var s = date.getFullYear();
		s = s + "-" + (date.getMonth()<9?"0":"") + (date.getMonth()+1);
		s = s + "-" + (date.getDate()<10?"0":"") + date.getDate();
		return s;
	} catch(e) {
		return "";
	}
}
/**
 * return hour in hh:mm format
 */
TaskCalculator.prototype._printHour = function(date) {
	try {
		var s = (date.getHours()<10?"0":"") + date.getHours();
		s = s + ":" + (date.getMinutes()<10?"0":"") + date.getMinutes();
		return s;
	} catch(e) {
		return "";
	}
}
/**
 * cholera, cienias jestem
 */
TaskCalculator.prototype._printSum = function(date) {
	try {
		var minutes = Math.round( date.getTime() / (60 * 1000) );
		var hh = Math.floor(minutes/60)
		var mm = minutes % 60;
		return hh + ":" + (mm<10?"0":"")+mm;
	} catch(e) {
		return "";
	}
}



/**
 * Parse calendar data
 */
TaskCalculator.prototype._onloadCallback = function(root) {
	this._parseEntries(root);
	this._createSummaryHtml();
	this._createMonthlyHtml();
	this._createAllHtml();
    this.onload();
}


















 
